package com.netsdk.config.websocket;

import com.netsdk.config.json.EnterDecoder;
import com.netsdk.config.json.EnterEncoder;
import com.netsdk.dto.EnterDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author aqie
 * @Date 2021/11/19 10:07
 * @desc websocket
 */
@Slf4j
@ServerEndpoint(value = "/ws/{uid}", decoders = {EnterDecoder.class}, encoders = {EnterEncoder.class})
@Component
public class WebSocketServer {
    private static final AtomicInteger onlineCount = new AtomicInteger(0);

    // concurrent包的线程安全Set，用来存放每个客户端对应的Session对象。
    private static Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        log.info("websocket 加载");
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "uid") String uid) {
        sessionMap.put(uid, session);

        int cnt = onlineCount.incrementAndGet(); // 在线数加1
        log.info("{} 连接加入，当前连接数为：{}", uid, cnt);
        sendMessage(uid, "连接成功");
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam(value = "uid") String uid) {
        sessionMap.remove(uid);
        int cnt = onlineCount.decrementAndGet();
        log.info("{} 连接关闭，当前连接数为：{}", uid, cnt);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     *            客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam(value = "uid") String uid) {
        log.info("来自客户端的消息：{}",message);
        sendMessage(uid, "收到消息，消息内容："+message);

    }

    /**
     * 出现错误
     * @param uid
     * @param error
     */
    @OnError
    public void onError(@PathParam(value = "uid") String uid, Throwable error) {
        log.error("发生错误：{}，uid： {}",error.getMessage(), uid);
        error.printStackTrace();
    }

    /**
     * 发送消息，实践表明，每次浏览器刷新，session会发生变化。
     * @param uid
     * @param message
     */
    public void sendMessage(String uid, String message) {
        try {
            Session session = sessionMap.get(uid);
            if(session != null && session.isOpen()){
                session.getBasicRemote().sendText(String.format("%s (From Server，uid=%s)",
                        message, uid));
            } else {
                log.info("{} 连接不存在", uid);
            }

        } catch (IOException e) {
            log.error("发送消息出错：{}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 群发消息
     * @param message
     */
    public void broadCastInfo(String message) {
        for (Map.Entry<String, Session> sessionEntry : sessionMap.entrySet()) {
            if(sessionEntry.getValue().isOpen()){
                sessionEntry.getValue().getAsyncRemote().sendText(message);
            }
        }
    }
    public void broadCastInfo(EnterDTO message) {
        for (Map.Entry<String, Session> sessionEntry : sessionMap.entrySet()) {
            if(sessionEntry.getValue().isOpen()){
                sessionEntry.getValue().getAsyncRemote().sendObject(message, new SendHandler() {
                    @Override
                    public void onResult(SendResult sendResult) {
                        log.info("SendHandler {}", sendResult.isOK());
                    }
                });
            }
        }
    }


}
